/*
 *  tracker/SampleEditorControlToolHandler.cpp
 *
 *  Copyright 2009 Peter Barth
 *
 *  This file is part of Milkytracker.
 *
 *  Milkytracker is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Milkytracker is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Milkytracker.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/*
 *  SampleEditorControlToolHandler.cpp
 *  MilkyTracker
 *
 *  Created by Peter Barth on 20.10.05.
 *
 */

#include "SampleEditorControl.h"
#include "DialogWithValues.h"
#include "DialogResample.h"
#include "DialogGroupSelection.h"
#include "DialogEQ.h"
#include "SimpleVector.h"
#include "FilterParameters.h"

bool SampleEditorControl::invokeToolParameterDialog(SampleEditorControl::ToolHandlerResponder::SampleToolTypes type)
{
    if (dialog)
    {
        delete dialog;
        dialog = NULL;
    }

    toolHandlerResponder->setSampleToolType(type);

    switch (type)
    {
        case ToolHandlerResponder::SampleToolTypeNew:
            dialog = new DialogWithValues(parentScreen, toolHandlerResponder, PP_DEFAULT_ID, "Create new sample" PPSTR_PERIODS, DialogWithValues::ValueStyleEnterOneValue);
            static_cast<DialogWithValues*>(dialog)->setValueOneCaption("Enter size in samples:");
            static_cast<DialogWithValues*>(dialog)->setValueOneRange(3, 1024 * 1024 * 10 - 1, 0);
            if (lastValues.newSampleSize != SampleEditorControlLastValues::invalidIntValue())
                static_cast<DialogWithValues*>(dialog)->setValueOne((float)lastValues.newSampleSize);
            else
                static_cast<DialogWithValues*>(dialog)->setValueOne(100.0f);
            break;

        case ToolHandlerResponder::SampleToolTypeVolume:
            dialog = new DialogWithValues(parentScreen, toolHandlerResponder, PP_DEFAULT_ID, "Boost sample volume" PPSTR_PERIODS, DialogWithValues::ValueStyleEnterOneValue);
            static_cast<DialogWithValues*>(dialog)->setValueOneCaption("Enter new volume in percent:");
            static_cast<DialogWithValues*>(dialog)->setValueOneRange(-10000.0f, 10000.0f, 2);
            static_cast<DialogWithValues*>(dialog)->setValueOne(lastValues.boostSampleVolume != SampleEditorControlLastValues::invalidFloatValue() ? lastValues.boostSampleVolume : 100.0f);
            break;

        case ToolHandlerResponder::SampleToolTypeFade:
            dialog = new DialogWithValues(parentScreen, toolHandlerResponder, PP_DEFAULT_ID, "Fade sample" PPSTR_PERIODS, DialogWithValues::ValueStyleEnterTwoValues);
            static_cast<DialogWithValues*>(dialog)->setValueOneCaption("Enter start volume in percent:");
            static_cast<DialogWithValues*>(dialog)->setValueTwoCaption("Enter end volume in percent:");
            static_cast<DialogWithValues*>(dialog)->setValueOneRange(-10000.0f, 10000.0f, 2);
            static_cast<DialogWithValues*>(dialog)->setValueTwoRange(-10000.0f, 10000.0f, 2);
            static_cast<DialogWithValues*>(dialog)->setValueOne(lastValues.fadeSampleVolumeStart != SampleEditorControlLastValues::invalidFloatValue() ? lastValues.fadeSampleVolumeStart : 100.0f);
            static_cast<DialogWithValues*>(dialog)->setValueTwo(lastValues.fadeSampleVolumeEnd != SampleEditorControlLastValues::invalidFloatValue() ? lastValues.fadeSampleVolumeEnd : 100.0f);
            break;

        case ToolHandlerResponder::SampleToolTypeDCOffset:
            dialog = new DialogWithValues(parentScreen, toolHandlerResponder, PP_DEFAULT_ID, "DC offset" PPSTR_PERIODS, DialogWithValues::ValueStyleEnterOneValue);
            static_cast<DialogWithValues*>(dialog)->setValueOneCaption("Enter offset in percent [-100..100]");
            static_cast<DialogWithValues*>(dialog)->setValueOneRange(-100, 100.0f, 2);
            static_cast<DialogWithValues*>(dialog)->setValueOne(lastValues.DCOffset != SampleEditorControlLastValues::invalidFloatValue() ? lastValues.DCOffset : 0.0f);
            break;

        case ToolHandlerResponder::SampleToolTypeResample:
            dialog = new DialogResample(parentScreen, toolHandlerResponder, PP_DEFAULT_ID);
            if (sampleEditor->isValidSample())
            {
                if (lastValues.resampleInterpolationType != SampleEditorControlLastValues::invalidIntValue())
                    static_cast<DialogResample*>(dialog)->setInterpolationType(lastValues.resampleInterpolationType);

                static_cast<DialogResample*>(dialog)->setAdjustFtAndRelnote(lastValues.adjustFtAndRelnote);

                static_cast<DialogResample*>(dialog)->setRelNote(sampleEditor->getRelNoteNum());
                static_cast<DialogResample*>(dialog)->setFineTune(sampleEditor->getFinetune());
                static_cast<DialogResample*>(dialog)->setSize(sampleEditor->getSampleLen());
            }
            break;

        case ToolHandlerResponder::SampleToolTypeEQ3Band:
            dialog = new DialogEQ(parentScreen, toolHandlerResponder, PP_DEFAULT_ID, DialogEQ::EQ3Bands);
            if (lastValues.hasEQ3BandValues)
            {
                for (pp_int32 i = 0; i < 3; i++)
                    static_cast<DialogEQ*>(dialog)->setBandParam(i, lastValues.EQ3BandValues[i]);
            }
            break;

        case ToolHandlerResponder::SampleToolTypeEQ10Band:
            dialog = new DialogEQ(parentScreen, toolHandlerResponder, PP_DEFAULT_ID, DialogEQ::EQ10Bands);
            if (lastValues.hasEQ10BandValues)
            {
                for (pp_int32 i = 0; i < 10; i++)
                    static_cast<DialogEQ*>(dialog)->setBandParam(i, lastValues.EQ10BandValues[i]);
            }
            break;

        case ToolHandlerResponder::SampleToolTypeGenerateSilence:
            dialog = new DialogWithValues(parentScreen, toolHandlerResponder, PP_DEFAULT_ID, "Insert silence" PPSTR_PERIODS, DialogWithValues::ValueStyleEnterOneValue);
            static_cast<DialogWithValues*>(dialog)->setValueOneCaption("Enter size in samples:");
            static_cast<DialogWithValues*>(dialog)->setValueOneRange(3, 1024 * 1024 * 10 - 1, 0);
            if (lastValues.silenceSize != SampleEditorControlLastValues::invalidIntValue())
                static_cast<DialogWithValues*>(dialog)->setValueOne((float)lastValues.silenceSize);
            else
                static_cast<DialogWithValues*>(dialog)->setValueOne(100.0f);
            break;

        case ToolHandlerResponder::SampleToolTypeGenerateNoise:
        {
            PPSimpleVector<PPString>noiseFilterTypes;

            noiseFilterTypes.add(new PPString("White"));
            noiseFilterTypes.add(new PPString("Pink"));
            noiseFilterTypes.add(new PPString("Brown"));

            dialog = new DialogGroupSelection(parentScreen,
                                              toolHandlerResponder,
                                              PP_DEFAULT_ID,
                                              "Select noise type" PPSTR_PERIODS,
                                              noiseFilterTypes);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeGenerateSine:
        case ToolHandlerResponder::SampleToolTypeGenerateSquare:
        case ToolHandlerResponder::SampleToolTypeGenerateTriangle:
        case ToolHandlerResponder::SampleToolTypeGenerateSawtooth:
        {
            dialog = new DialogWithValues(parentScreen, toolHandlerResponder, PP_DEFAULT_ID, "Generate waveform" PPSTR_PERIODS, DialogWithValues::ValueStyleEnterTwoValues);
            static_cast<DialogWithValues*>(dialog)->setValueOneCaption("Volume in percent:");
            static_cast<DialogWithValues*>(dialog)->setValueTwoCaption("Number of periods:");
            static_cast<DialogWithValues*>(dialog)->setValueOneRange(-1000.0f, 1000.0f, 2);
            static_cast<DialogWithValues*>(dialog)->setValueTwoRange(0.0f, 1000.0f, 1);
            static_cast<DialogWithValues*>(dialog)->setValueOne(lastValues.waveFormVolume != SampleEditorControlLastValues::invalidFloatValue() ? lastValues.waveFormVolume : 100.0f);
            static_cast<DialogWithValues*>(dialog)->setValueTwo(lastValues.waveFormNumPeriods != SampleEditorControlLastValues::invalidFloatValue() ? lastValues.waveFormNumPeriods : 1.0f);
            break;
        }

    }

    dialog->show();

    return true;
}

bool SampleEditorControl::invokeTool(ToolHandlerResponder::SampleToolTypes type)
{
    if (!sampleEditor->isValidSample())
        return false;

    switch (type)
    {
        case ToolHandlerResponder::SampleToolTypeNew:
        {
            FilterParameters par(2);
            lastValues.newSampleSize = (pp_int32) static_cast<DialogWithValues*>(dialog)->getValueOne();
            par.setParameter(0, FilterParameters::Parameter(lastValues.newSampleSize));
            par.setParameter(1, FilterParameters::Parameter(sampleEditor->is16Bit() ? 16 : 8));
            sampleEditor->tool_newSample(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeVolume:
        {
            lastValues.boostSampleVolume = static_cast<DialogWithValues*>(dialog)->getValueOne();
            FilterParameters par(2);
            par.setParameter(0, FilterParameters::Parameter(lastValues.boostSampleVolume / 100.0f));
            par.setParameter(1, FilterParameters::Parameter(lastValues.boostSampleVolume / 100.0f));
            sampleEditor->tool_scaleSample(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeFade:
        {
            lastValues.fadeSampleVolumeStart = static_cast<DialogWithValues*>(dialog)->getValueOne();
            lastValues.fadeSampleVolumeEnd = static_cast<DialogWithValues*>(dialog)->getValueTwo();
            FilterParameters par(2);
            par.setParameter(0, FilterParameters::Parameter(lastValues.fadeSampleVolumeStart / 100.0f));
            par.setParameter(1, FilterParameters::Parameter(lastValues.fadeSampleVolumeEnd / 100.0f));
            sampleEditor->tool_scaleSample(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeDCOffset:
        {
            FilterParameters par(1);
            lastValues.DCOffset = static_cast<DialogWithValues*>(dialog)->getValueOne();
            par.setParameter(0, FilterParameters::Parameter(lastValues.DCOffset / 100.0f));
            sampleEditor->tool_DCOffsetSample(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeResample:
        {
            lastValues.resampleInterpolationType = static_cast<DialogResample*>(dialog)->getInterpolationType();
            lastValues.adjustFtAndRelnote = static_cast<DialogResample*>(dialog)->getAdjustFtAndRelnote();

            FilterParameters par(3);
            par.setParameter(0, FilterParameters::Parameter(static_cast<DialogResample*>(dialog)->getC4Speed()));
            par.setParameter(1, FilterParameters::Parameter(static_cast<pp_int32>(lastValues.resampleInterpolationType)));
            par.setParameter(2, FilterParameters::Parameter(lastValues.adjustFtAndRelnote ? 1 : 0));
            sampleEditor->tool_resampleSample(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeEQ3Band:
        case ToolHandlerResponder::SampleToolTypeEQ10Band:
        {
            pp_uint32 numBands = static_cast<DialogEQ*>(dialog)->getNumBandsAsInt();

            float* last = NULL;

            if (numBands == 3)
            {
                lastValues.hasEQ3BandValues = true;
                last = lastValues.EQ3BandValues;
            }
            else
            {
                lastValues.hasEQ10BandValues = true;
                last = lastValues.EQ10BandValues;
            }

            FilterParameters par(numBands);
            for (pp_uint32 i = 0; i < numBands; i++)
            {
                float val = static_cast<DialogEQ*>(dialog)->getBandParam(i);
                if (last)
                    last[i] = val;
                par.setParameter(i, FilterParameters::Parameter(val));
            }
            sampleEditor->tool_eqSample(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeGenerateSilence:
        {
            FilterParameters par(1);
            par.setParameter(0, FilterParameters::Parameter((pp_int32)(static_cast<DialogWithValues*>(dialog)->getValueOne())));
            sampleEditor->tool_generateSilence(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeGenerateNoise:
        {
            FilterParameters par(1);
            par.setParameter(0, FilterParameters::Parameter((pp_int32)(static_cast<DialogGroupSelection*>(dialog)->getSelection())));
            sampleEditor->tool_generateNoise(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeGenerateSine:
        {
            lastValues.waveFormVolume = static_cast<DialogWithValues*>(dialog)->getValueOne();
            lastValues.waveFormNumPeriods = static_cast<DialogWithValues*>(dialog)->getValueTwo();
            FilterParameters par(2);
            par.setParameter(0, FilterParameters::Parameter(lastValues.waveFormVolume / 100.0f));
            par.setParameter(1, FilterParameters::Parameter(lastValues.waveFormNumPeriods));
            sampleEditor->tool_generateSine(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeGenerateSquare:
        {
            lastValues.waveFormVolume = static_cast<DialogWithValues*>(dialog)->getValueOne();
            lastValues.waveFormNumPeriods = static_cast<DialogWithValues*>(dialog)->getValueTwo();
            FilterParameters par(2);
            par.setParameter(0, FilterParameters::Parameter(lastValues.waveFormVolume / 100.0f));
            par.setParameter(1, FilterParameters::Parameter(lastValues.waveFormNumPeriods));
            sampleEditor->tool_generateSquare(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeGenerateTriangle:
        {
            lastValues.waveFormVolume = static_cast<DialogWithValues*>(dialog)->getValueOne();
            lastValues.waveFormNumPeriods = static_cast<DialogWithValues*>(dialog)->getValueTwo();
            FilterParameters par(2);
            par.setParameter(0, FilterParameters::Parameter(lastValues.waveFormVolume / 100.0f));
            par.setParameter(1, FilterParameters::Parameter(lastValues.waveFormNumPeriods));
            sampleEditor->tool_generateTriangle(&par);
            break;
        }

        case ToolHandlerResponder::SampleToolTypeGenerateSawtooth:
        {
            lastValues.waveFormVolume = static_cast<DialogWithValues*>(dialog)->getValueOne();
            lastValues.waveFormNumPeriods = static_cast<DialogWithValues*>(dialog)->getValueTwo();
            FilterParameters par(2);
            par.setParameter(0, FilterParameters::Parameter(lastValues.waveFormVolume / 100.0f));
            par.setParameter(1, FilterParameters::Parameter(lastValues.waveFormNumPeriods));
            sampleEditor->tool_generateSawtooth(&par);
            break;
        }
    }

    return true;
}

SampleEditorControl::ToolHandlerResponder::ToolHandlerResponder (SampleEditorControl& theSampleEditorControl) :
    sampleEditorControl(theSampleEditorControl),
    sampleToolType(SampleToolTypeNone)
{
}

pp_int32 SampleEditorControl::ToolHandlerResponder::ActionOkay(PPObject* sender)
{
    sampleEditorControl.invokeTool(sampleToolType);
    return 0;
}

pp_int32 SampleEditorControl::ToolHandlerResponder::ActionCancel(PPObject* sender)
{
    return 0;
}